1. Field of the Invention
The present invention relates generally to computer software. More particularly, the present invention relates to memory management with non-compacting garbage collection.
2. Description of the Relevant Art
The term xe2x80x9cmemory managementxe2x80x9d generally denotes a collection of techniques for providing sufficient memory to one or more processes in a computer system, especially when the system does not have enough memory to satisfy all processes"" requirements simultaneously. Memory management techniques include swapping, paging, virtual memory, and garbage collection. Memory management is usually performed primarily by a hardware memory management unit. Automatic memory management refers to memory management processes which do not require user intervention.
In general, the overheads of automatic memory management can be attributed to allocations of new data structures (e.g., objects), detecting alive (i.e., reachable) objects, disposing of unreachable objects, and memory compaction. Some algorithms do not have all of the above components, and various algorithms differ substantially in the amount of overhead contributed by each of the above-listed components. For example, a mark-and-sweep algorithm may spend a significant amount of time on sweeping memory and merging discovered free blocks into larger contiguous regions, while the main source of overhead of copying-based garbage collection comes from memory compaction. Different algorithms behave differently with respect to space as well; non-copying algorithms typically do not prevent memory fragmentation at all while copying algorithms compact memory to reduce fragmentation.
One of the primary problems encountered in memory management is fragmentation, which is the process or result of splitting a large area of free memory (e.g., on disk or in main memory) into smaller non-contiguous blocks. Fragmentation may occur after many blocks have been allocated and freed. For example, if there are three kilobytes of free space and two 1 k blocks are allocated and then the first one (at the lowest address) is freed, then there will be 2 k of free space split between the two 1 k blocks. The maximum size block that could then be allocated would be 1 k even though there are 2 k free. One solution is to xe2x80x9ccompactxe2x80x9d the free space by moving the allocated blocks to one end (and thus the free space to the other). Fragmentation related to RAM that has small, unused holes scattered throughout it is called external fragmentation. With modem operating systems that use a paging scheme, a more common type of RAM fragmentation is internal fragmentation. Internal fragmentation occurs when memory is allocated in frames, and the frame size is larger than the amount of memory requested.
Garbage collection is the process by which dynamically allocated storage is reclaimed during the execution of a program. The term usually refers to automatic periodic storage reclamation by the garbage collector (usually part of the run-time system), as opposed to explicit code to free specific blocks of memory. Automatic garbage collection is usually triggered during memory allocation when the amount of free memory falls below some threshold or after a certain number of allocations. Normal execution is suspended and the garbage collector is run. There are many variations on this basic scheme. Languages like Lisp represent expressions as graphs built from cells which contain pointers and data. These languages use automatic dynamic storage allocation to build expressions. During the evaluation of an expression it is necessary to reclaim space which is used by sub expressions but which is no longer pointed to by anything. This reclaimed memory is returned to the free memory pool for subsequent reallocation. Without garbage collection the program""s memory requirements would increase monotonically throughout execution, possibly exceeding system limits on virtual memory size. The three main methods are mark-and-sweep garbage collection, reference counting, and copying garbage collection.
In the mark-and-sweep garbage collection scheme, each cell has a bit reserved for marking which is clear initially. During garbage collection, all active cells are traced from the root and marked. Then all cells are examined and unmarked cells are freed.
In the reference counting scheme, each memory cell contains a count of the number of other cells which point to it. If this count reaches zero, the cell is freed and its pointers to other cells are followed to decrement their counts, and so on recursively. This technique cannot cope with circular data structures. Cells in such structures refer (indirectly) to themselves and so will never have a zero reference count. This means they would never be reclaimed, even when there are no references from outside the structure.
In copying-based garbage collection schemes, memory is typically divided into two equal halves, known as the xe2x80x9cfrom spacexe2x80x9d and xe2x80x9cto space.xe2x80x9d Garbage collection copies active cells from the xe2x80x9cfrom spacexe2x80x9d to the xe2x80x9cto spacexe2x80x9d and leaves behind an invisible pointer (an xe2x80x9cindirectionxe2x80x9d) from the old position to the new copy. Once all active cells have been copied in one direction, the spaces are swapped and the process is repeated in the opposite direction. Each time the cells are copied from one space to the other, they are compacted to remove any unused space between them.
A garbage collector must determine which data structures, such as objects, are in use and which are not. A program executing a set of methods may have arguments or local variables that are references to objects. These references are said to belong to a root set of references that are immediately accessible to the program. All objects referenced by this root set of references are said to be reachable by the program in its current state and should not be collected by a garbage collector. Also, those objects might contain references to still other objects, which are also reachable, and so on. All other objects on the heap are considered unreachable, and all unreachable objects are typically eligible for garbage collection and may be reclaimed during garbage collection. Garbage collection algorithms vary, but they typically have in common the task of identifying the objects that are reachable from the root set and reclaiming the space occupied by any other objects. An object may refer to reachable objects and still be unreachable itself. Likewise, an object can be unreachable in spite of references to it, if those references are all from unreachable objects.
Statistical studies show that most objects are small. Many implementations of automatic memory management algorithms take this into account, for instance, by pre-allocating larger chunks of memory and then using them for fast allocation space for small objects. However, fragmentation may still present memory management problems when many of the small objects are allocated and de-allocated during program execution. Memory management approaches to fragmentation which rely upon copying, such as compaction schemes, may require significant overhead, yet the problems associated with memory fragmentation typically require compaction to be solved. Similarly, when many small, short-lived objects are allocated and de-allocated, discovering unreachable objects and making unreachable memory available for allocations may incur large overheads.
Therefore, an improved system and method for memory management are desired.
The problems outlined above are in large part solved by various embodiments of a system and method for memory management. In one embodiment, a memory heap comprises a plurality of memory blocks of a uniform and fixed size. The uniform size of the memory blocks removes the need for variable-size memory block management, which may be substantial in that variable-size memory blocks must have size information associated with them, and the memory manager must read and manage this information. In one embodiment, each memory block in the heap may have associated with it a status bit indicating that block""s current allocation status. In one embodiment, a binary status key stores a Boolean value indicating free memory. Any memory block in the heap whose status bit holds this value is considered to be free for allocation. Memory allocation from the heap may be performed by a memory management program.
A memory allocation process for a partitioned data structure from a heap of fixed-size memory blocks may be used to mitigate problems related to memory fragmentation in non-compacting memory allocation and garbage collection systems. The method may also be used as a xe2x80x9clast resortxe2x80x9d method when allocation under a non-compacting garbage collection scheme has failed. A request may be received to allocate storage for a data structure from a heap of uniform and fixed-size memory blocks. In one embodiment, the data structure may be an object in an object-oriented language such as C++ or the Java(trademark) Language. The data structure may also include any primitive data type (e.g., an integer, floating point number, character, etc.), array, or structured data type. Each of the blocks in the heap may be of a uniform fixed size to improve the efficiency of the memory management process.
The size of the structure may be determined by partitioning the structure into one or more components in a particular order, wherein each of the one or more components does not exceed the fixed size of the fixed-size memory blocks, and determining a quantity of the plurality of memory blocks required to store the components of the structure. The required quantity of the memory blocks may then be allocated from the heap. In one embodiment, the allocated quantity of memory blocks may include at least two noncontiguous memory blocks. Finally, the allocated memory blocks may be linked in a list such that the components of the structure are partitioned in the particular order of the components across the allocated quantity of memory blocks.
In one embodiment, the data structure may be an object, and allocating memory for the object may further include instantiating the object in the allocated quantity of memory blocks.
Further optimizations may be employed with the system and method described above. In one embodiment, the components of the structure may be reordered such that rarely accessed components of the structure are placed at the end of the component order before linking the allocated memory blocks. In one embodiment, allocating space for arrays or other large data structures may result in many xe2x80x9chopsxe2x80x9d (i.e., traversal of many links) to reach array entries with high index values. This problem may be mitigated by laying array entries as leaves of a binary tree, in which case access time for array entries is proportional to log (array size).